package com.amkai.aes.webservice.binary.objecthandler.contract;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.hibernate.Query;

import com.amkai.aes.aescommon.contract.ContractCalculationManager;
import com.amkai.aes.aescommon.exceptions.ContractCalculationException;
import com.amkai.aes.aescommon.factory.RADBeanFactory;
import com.amkai.aes.aescommon.service.binary.job.contract.ContractImportJob;
import com.amkai.aes.aescommon.service.result.contract.ContractImportResult;
import com.amkai.aes.generatedbeans.contract.Contract;
import com.amkai.aes.generatedbeans.contract.ContractProcedure;
import com.amkai.aes.generatedbeans.contract.ContractType;
import com.amkai.aes.generatedbeans.contract.FeeGroup;
import com.amkai.aes.generatedbeans.procedure.Procedure;
import com.amkai.aes.server.dictionary.ServerContractManager;
import com.amkai.aes.webservice.binary.JobObjectHandler;
import com.amkai.common.extensions.hibernate.config.SiteManager;
import com.amkai.common.extensions.hibernate.config.manager.SessionManager;
import com.amkai.rad.designerbase.beans.RADBean;

public class ContractImportHandler implements JobObjectHandler<ContractImportJob, Serializable, ContractImportResult> {

	@Override
	public ContractImportResult process(ContractImportJob job, Serializable object) throws Exception {
		ContractImportResult result = null;
		SessionManager sm = SiteManager.Start();
		switch (job.getKind()) {
		case GET_CONTRACT_WITH_NON_COVERED_INITIALIZATION_OPTION:
			result = processContractWithNonCoveredOption(sm, job);
			break;
		case GET_CONTRACT_PROCEDURES:
			result = getContractProcedures(sm, job);
			break;

		default:
			break;
		}
		return result;
	}

	private ContractImportResult getContractProcedures(SessionManager sm, ContractImportJob job) throws Exception {
		ContractImportResult result = new ContractImportResult();
		
		for (String[] names : job.getContractCPTnames()) {
		
			Long contractId = Long.valueOf(names[0]);
			String cpt = names[1];
			
			ContractProcedure cp = (ContractProcedure) sm.execute(
					"FROM ContractProcedure WHERE contract.id = :cid AND procedure.shortName = :psn AND procedure.active = 1").setString("psn", cpt)
					.setLong("cid", contractId).uniqueResult();

			if (cp != null) {
				cp.getProcedure().getShortName();

				if (cp.getFeeGroup() != null) {
					cp.getFeeGroup().getSequence();
				}
				result.getContractProcedures().add(cp);

			} else {
				Long procedure = (Long) sm.execute("SELECT id FROM Procedure WHERE baseOrganization = :dep AND active = 1 AND shortName = :sn")
						.setEntity("dep", job.getModuleDepartment()).setString("sn", cpt).uniqueResult();
				if (procedure != null) {
					cp = ServerContractManager.findContractProcedureWithNoChecking(sm, contractId, procedure, job.getContractProcedureType());
					sm.saveRADInTransaction(cp);
					result.getContractProcedures().add(cp);
				}
			}
		}

		return result;
	}

	

	@SuppressWarnings("unchecked")
	protected ContractImportResult processContractWithNonCoveredOption(SessionManager sm, ContractImportJob job) throws Exception {
		
		ContractImportResult result = new ContractImportResult();
	
		List<Contract> contracts = sm.execute("FROM Contract WHERE shortName in ( :list ) and baseOrganization.id = :boid").setLong("boid",
				job.getModuleDepartment().getId()).setParameterList("list", job.getContractShortNameWithNonCoveredProceduresHandling().keySet())
				.list();
		
		List<Long> procedures = sm.execute("SELECT id FROM Procedure WHERE baseOrganization.id = :boid AND active = 1 ").setLong("boid",
				job.getModuleDepartment().getId()).list();
		
		Set<String> existShortNames = new HashSet<String>();
		
		for (Contract contract : contracts) {

			if (needNonCoveredProcessing(sm, job, contract.getId(), existShortNames)) {

				for (Long procedure : procedures) {
					ContractProcedure cp = ServerContractManager.findContractProcedure(sm, contract.getId(), procedure, ContractType.NON_COVERED);
					// KKORNEL: AES-14883 - Set the contract to non-covered if the type is not non-covered
					if (cp.getContractType() != ContractType.NON_COVERED) {
						cp.setContractType(ContractType.NON_COVERED);
						cp.setAppendedFee(null);
						cp.setFeeGroup(null);
						cp.setApcAmount(null);
						cp.setAllowedAmount(null);
					}
					sm.saveRADInTransaction(cp);
					//System.out.println(contract.getId() + " " + procedure);
					sm.clear();
				}
			}
		}

		job.getContractShortNameWithNonCoveredProceduresHandling().keySet().removeAll(existShortNames);
		result.getNotExistsContractNames().addAll(job.getContractShortNameWithNonCoveredProceduresHandling().keySet());
		for (Contract contract : contracts) {
			loadContractFeeGroup(sm, contract);
		}
		result.setExistContracts(contracts);
		
		return result;
	}

	@SuppressWarnings("unchecked")
	private void loadContractFeeGroup(SessionManager sm, Contract contract) {
		contract.setFeeGroups(new HashSet<FeeGroup>());
		Query q = sm.execute("SELECT id, sequence FROM FeeGroup where contract = :c ORDER BY sequence").setEntity("c", contract);
		for (Iterator it = q.iterate(); it.hasNext();) {
			FeeGroup fg = RADBeanFactory.getInstance().createBean(FeeGroup.class);
			Object[] row = (Object[]) it.next();
			fg.setId((Long) row[0]);
			fg.setSequence((Integer) row[1]);
			contract.getFeeGroups().add(fg);
		}
	}

	private boolean needNonCoveredProcessing(SessionManager sm, ContractImportJob job, Long contractId, Set<String> existShortNames) throws Exception {
		boolean result = false;
		Contract c = sm.get(Contract.class, contractId);
		existShortNames.add(c.getShortName());
		if (job.getContractShortNameWithNonCoveredProceduresHandling().get(c.getShortName())) {
			result = true;
		}
		return result;
	}



}
